package com.sutong.gateway.filter;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.sutong.common.service.RemoteInterfaceInfoService;
import com.sutong.common.service.RemoteUserService;
import com.sutong.common.utils.Constant;
import com.sutong.common.utils.SignUtils;
import com.sutong.gateway.properties.BlackListProperties;
import com.sutong.gateway.utils.GatewayHttpUtil;
import com.sutong.gateway.utils.WebFluxResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;

/**
 * 全局过滤器
 *
 * @author sutong
 * @date 2024-07-14 18:31
 */
@Slf4j
@Component
public class VerifyFilter implements GlobalFilter, Ordered {

    /**
     * 黑名单
     */
    @Resource
    private BlackListProperties blackListProperties;

    @DubboReference
    private RemoteUserService remoteUserService;

    @DubboReference
    private RemoteInterfaceInfoService remoteInterfaceInfoService;

    private static final long FIVE_MINUTE = 5L * 60 * 1000;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();

        // 黑名单
        String ip = request.getRemoteAddress().getHostString();
        if (blackListProperties.getBlack().contains(ip)) {
            return WebFluxResultUtils.error(exchange.getResponse(), "你在黑名单");
        }

        // 鉴权
        // 随机数校验
        String nonce = request.getHeaders().getFirst(Constant.NONCE);
        if (NumberUtil.parseLong(nonce) > 10000) {
            return WebFluxResultUtils.error(exchange.getResponse(), "随机数校验失败");
        }

        // 时间校验 时间和当前时间不能超过 5 分钟
        String timestamp = request.getHeaders().getFirst(Constant.TIMESTAMP);
        if (System.currentTimeMillis() - NumberUtil.parseLong(timestamp) > FIVE_MINUTE) {
            return WebFluxResultUtils.error(exchange.getResponse(), "时间校验失败");
        }

        // RPC，去数据库中查接口是否存在
        String url = request.getURI().toString();
        String method = request.getMethod().toString();
        Long interfaceId = remoteInterfaceInfoService.verifyInterfaceExists(url, method);
        if (ObjectUtil.isNull(interfaceId)) {
            return WebFluxResultUtils.error(exchange.getResponse(), "接口不存在");
        }

        // TODO 验证用户是否有调用次数

        // RPC，去数据库中查是否已分配给用户
        String accessKey = request.getHeaders().getFirst(Constant.ACCESS_KEY);
        String serverSecretKey = remoteUserService.getSecretKey(accessKey);
        if (StrUtil.isBlank(serverSecretKey)) {
            return WebFluxResultUtils.error(exchange.getResponse(), "该AccessKey无效");
        }

        // 验证服务器计算的签名和header里面的签名是否一致
        String bodyStr = GatewayHttpUtil.getRequestBody(exchange);
        String serverSignature = SignUtils.signature(serverSecretKey, request, bodyStr);
        String signature = request.getHeaders().getFirst(Constant.SIGNATURE);
        if (!serverSignature.equals(signature)) {
            return WebFluxResultUtils.error(exchange.getResponse(), "验签失败");
        }
        exchange.getAttributes().put(Constant.ACCESS_KEY_STR, accessKey);
        exchange.getAttributes().put(Constant.INTERFACE_ID_STR, interfaceId);
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }

}
